package com.barney.support.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

/**
 * <code>web.xml</code>의 필터 설정을 변경하지 않고 프로퍼티등으로 필터를 사용할 지 여부를 정할 수 있도록 지원하는
 * 필터. <code>skip</code>이 <code>true</code> 일 때는 실행하지 않는다.<br/>
 * <br/>
 * <code>web.xml</code>파일에는 {@link org.springframework.web.filter.DelegatingFilterProxy}를 사용하고
 * <code>init-param</code>으로 <code>targetFilterLifecycle</code>의 값을 <code>true</code>로 지정하고,
 * 실제 실행될 필터의 매개변수를 <code>init-param</code>에 지정한다.
 * <br/>
 * <code>applicationContext.xml</code>파일에는 <code>web.xml</code>에서 지정한 필터명에 대한
 * 실제 필터 클래스를 설정하고 <code>skip</code> 값을 설정한다.
 * <br/>
 * 사용 예는 다음과 같다.
 * <blockquote><pre>
 * <code>web.xml</code> 파일
 *
 * &lt;filter&gt;
 *   &lt;filter-name&gt;w3cMarkupValidationFilter&lt;/filter-name&gt;
 *   &lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;
 *   &lt;init-param&gt;
 *     &lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;
 *     &lt;param-value&gt;true&lt;/param-value&gt;
 *   &lt;/init-param&gt;
 * &lt;/filter&gt;
 * &lt;filter-mapping&gt;
 *   &lt;filter-name&gt;w3cMarkupValidationFilter&lt;/filter-name&gt;
 *   &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
 * &lt;/filter-mapping&gt;
 * </pre></blockquote>
 *
 * <blockquote><pre>
 * <code>applicationContext.xml</code>파일
 *
 * &lt;bean name="w3cMarkupValidationFilter" class="com.barney.support.web.filter.SkippableFilter"&gt;
 *   &lt;property name="delegateFilter"&gt;
 *     &lt;bean class="de.michaeltamm.W3cMarkupValidationFilter"/&gt;
 *   &lt;/property&gt;
 *   &lt;property name="skip" value="true"/&gt;
 * &lt;/bean&gt;
 * </pre></blockquote>
 *
 * @see org.springframework.web.filter.DelegatingFilterProxy
 */
public class SkippableFilter implements Filter, InitializingBean {

	private boolean skip = false;

	private Filter delegateFilter;

	public boolean isSkip() {
		return skip;
	}

	public void setSkip(boolean skip) {
		this.skip = skip;
	}

	public Filter getDelegateFilter() {
		return delegateFilter;
	}

	public void setDelegateFilter(Filter delegateFilter) {
		this.delegateFilter = delegateFilter;
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		delegateFilter.init(filterConfig);
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		if (skip) {
			chain.doFilter(request, response);
		} else {
			delegateFilter.doFilter(request, response, chain);
		}
	}

	@Override
	public void destroy() {
		this.delegateFilter.destroy();
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(getDelegateFilter());
	}

}
